/*
@file: EnDecrypt.cpp
@author: ZZH
@time: 2022-10-31 17:38:06
@info: 加解密实现
*/
#include "EnDecrypt.h"
#include "Mat.h"

namespace AES
{
    size_t encrypt(void* output, const void* data, const void* key, size_t len)
    {
        size_t mod = len % 16;
        size_t num = len / 16;
        size_t all = num + 1;//填充必然存在, 因此需要多一个Mat
        Mat_t k(static_cast<const uint8_t*>(key));
        const uint8_t* pData = static_cast<const uint8_t*>(data);

        auto pMats = new Mat_t[all];//创建足够数量的mat对象

        for (size_t i = 0;i < num;i++, pData += 16)//处理整数数量字节
            pMats[i].setData(pData);

        if (mod != 0)
            pMats[num].setData(pData, mod);//剩余部分
        else
            pMats[num].fill(16);//PKCS7填充

        for (int j = 0;j < all;j++)//首先进行一遍密钥加法
            pMats[j] ^= k;//密钥加法

        for (int i = 0;i < 9;i++)//逐轮加密, AES128需要10轮加密, 前9轮的处理是一样的
        {
            for (size_t j = 0;j < all;j++)
            {
                pMats[j].byteReplace();//字节代换
                pMats[j].shiftRows();//行移位
                pMats[j].mixColumn();//列混淆
                pMats[j] ^= k;//密钥加法
            }
        }

        for (size_t j = 0;j < all;j++)//最后一轮加密操作不同
        {
            pMats[j].byteReplace();//字节代换
            pMats[j].shiftRows();//行移位
            // pMats[j].mixColumn();//列混淆
            pMats[j] ^= k;//密钥加法
        }

        uint8_t* out = static_cast<uint8_t*>(output);
        for (int i = 0;i < all;i++)
        {
            pMats[i].getData(out);
            out += 16;
        }

        delete[] pMats;

        return all * 16;
    }

    size_t decrypt(void* output, const void* data, const void* key, size_t len)
    {
        size_t num = len / 16;
        Mat_t k(static_cast<const uint8_t*>(key));
        const uint8_t* pData = static_cast<const uint8_t*>(data);

        auto pMats = new Mat_t[num];//创建足够数量的mat对象

        for (size_t i = 0;i < num;i++, pData += 16)//处理整数数量字节
            pMats[i].setData(pData);

        for (size_t j = 0;j < num;j++)//第一轮解密操作不同
        {
            pMats[j] ^= k;//密钥加法
            // pMats[j].imixColumn();//逆列混淆
            pMats[j].ishiftRows();//逆行移位
            pMats[j].ibyteReplace();//逆字节代换
        }

        for (int i = 0;i < 9;i++)//逐轮解密, AES128需要10轮解密, 前9轮的处理是一样的
        {
            for (size_t j = 0;j < num;j++)
            {
                pMats[j] ^= k;//密钥加法
                pMats[j].imixColumn();//逆列混淆
                pMats[j].ishiftRows();//逆行移位
                pMats[j].ibyteReplace();//逆字节代换
            }
        }

        for (int j = 0;j < num;j++)//首先进行一遍密钥加法
            pMats[j] ^= k;//密钥加法

        uint8_t* out = static_cast<uint8_t*>(output);
        size_t decryptNum = num - 1;//最后一个Mat是填充mat, 可能是部分填充也可能全是填充
        for (int i = 0;i < decryptNum;i++)
        {
            pMats[i].getData(out);
            out += 16;
        }

        const Mat_t& lastMat = pMats[decryptNum];
        lastMat.getUnFilledPart(out);
        size_t dataLen = decryptNum * 16 + lastMat.getUnFilledLen();//计算实际数据长度

        delete[] pMats;

        return dataLen;
    }
} // namespace AES

